package com.myzl.coal.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.*;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myzl.coal.domain.RealTimeData;
import com.myzl.coal.domain.Statistics;
import com.myzl.coal.domain.vo.AverageThicknessVO;
import com.myzl.coal.domain.vo.BriefingVO;
import com.myzl.coal.domain.vo.ComparisonVO;
import com.myzl.coal.dto.LedScreenDTO;
import com.myzl.coal.mapper.RealTimeDataMapper;
import com.myzl.coal.mapper.StatisticsMapper;
import com.myzl.coal.mongo.component.MongoComponent;
import com.myzl.coal.mongo.domain.HistoryData;
import com.myzl.coal.service.IRealTimeDataService;
import com.myzl.coal.utils.CalculationUtils;
import com.myzl.coal.webSocket.WebSocket;
import com.myzl.common.constant.CacheKeyConstants;
import com.myzl.common.core.domain.AjaxResult;
import com.myzl.common.core.domain.entity.SysDictData;
import com.myzl.common.core.redis.RedisCache;
import com.myzl.common.enums.*;
import com.myzl.common.utils.DateUtils;
import com.myzl.common.utils.DictUtils;
import com.myzl.common.utils.SpecificDateUtil;
import com.myzl.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 实时数据Service业务层处理
 *
 * @author myzl
 * @date 2022-09-01
 */
@Service
@Slf4j
public class RealTimeDataServiceImpl extends ServiceImpl<RealTimeDataMapper, RealTimeData> implements IRealTimeDataService {
    @Autowired
    private RealTimeDataMapper realTimeDataMapper;
    @Autowired
    private MongoComponent mongoComponent;
    @Autowired
    private WebSocket webSocket;
    @Autowired
    private DemoService demoService;
    @Autowired
    private StatisticsMapper statisticsMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 查询实时数据
     *
     * @param id 实时数据主键
     * @return 实时数据
     */
    @Override
    public RealTimeData selectRealTimeDataById(String id) {
        return realTimeDataMapper.selectRealTimeDataById(id);
    }


    /**
     * 查询实时数据列表
     *
     * @param realTimeData 实时数据
     * @return 实时数据
     */
    @Override
    public List<RealTimeData> selectRealTimeDataList(RealTimeData realTimeData) {
        return realTimeDataMapper.selectRealTimeDataList(realTimeData);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRealTimeDeviceStatus(Integer id, StatusStringType statusStringType) {
        RealTimeData params = new RealTimeData();
        params.setDeviceId(id);
        params.setDictValue(PublicDictValueEnum.DEVICE_STATUS.getCode());
        List<RealTimeData> realTimeDataList = selectRealTimeDataList(params);
        if (!CollectionUtils.isEmpty(realTimeDataList)) {
            RealTimeData realTimeData = realTimeDataList.get(0);
            if (!Objects.equals(realTimeData.getDataValue(), statusStringType.getCode())) {
                realTimeData.setDataValue(statusStringType.getCode());
                updateRealTimeData(realTimeData);
                if (!WebSocket.webSocketMap.isEmpty()) {
                    JSONObject json = webSocket.getJsonObject(id, PublicDictValueEnum.DEVICE_STATUS.getCode(), Integer.parseInt(statusStringType.getCode()), "");
                    webSocket.sendMessage(json.toString());
                }

            }
        }
    }

    /**
     * 新增实时数据
     *
     * @param realTimeData 实时数据
     * @return 结果
     */
    @Override
    public int insertRealTimeData(RealTimeData realTimeData) {
        realTimeData.setCreateTime(DateUtils.getNowDate());
        return realTimeDataMapper.insertRealTimeData(realTimeData);
    }

    /**
     * 修改实时数据
     *
     * @param realTimeData 实时数据
     * @return 结果
     */
    @Override
    public int updateRealTimeData(RealTimeData realTimeData) {
        realTimeData.setUpdateTime(DateUtils.getNowDate());
        return realTimeDataMapper.updateRealTimeData(realTimeData);
    }

    /**
     * 批量删除实时数据
     *
     * @param ids 需要删除的实时数据主键
     * @return 结果
     */
    @Override
    public int deleteRealTimeDataByIds(String[] ids) {
        return realTimeDataMapper.deleteRealTimeDataByIds(ids);
    }

    /**
     * 删除实时数据信息
     *
     * @param id 实时数据主键
     * @return 结果
     */
    @Override
    public int deleteRealTimeDataById(String id) {
        return realTimeDataMapper.deleteRealTimeDataById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateRealTimeDataByType(List<RealTimeData> list) {
        list.forEach(e -> {
            RealTimeData realTimeData = new RealTimeData();
            realTimeData.setDeviceType(e.getDeviceType());
            realTimeData.setDeviceId(e.getDeviceId());
            realTimeData.setDictValue(e.getDictValue());
            List<RealTimeData> realTimeDataList = selectRealTimeDataList(realTimeData);

            if (realTimeDataList.size() > 0) {
                LambdaUpdateWrapper<RealTimeData> lambdaUpdateWrapper = new LambdaUpdateWrapper<RealTimeData>();
                lambdaUpdateWrapper.eq(RealTimeData::getDeviceType, e.getDeviceType());
                lambdaUpdateWrapper.eq(RealTimeData::getDeviceId, e.getDeviceId());
                lambdaUpdateWrapper.eq(RealTimeData::getDictValue, e.getDictValue());
                lambdaUpdateWrapper.set(RealTimeData::getDataValue, e.getDataValue());
                if (e.getCreateTime() != null) {
                    lambdaUpdateWrapper.set(RealTimeData::getUpdateTime, e.getCreateTime());
                } else {
                    lambdaUpdateWrapper.set(RealTimeData::getUpdateTime, new Date());
                }
                if (Objects.nonNull(e.getRemark())) {
                    lambdaUpdateWrapper.set(RealTimeData::getRemark, e.getRemark());
                }
                boolean update = update(lambdaUpdateWrapper);

            } else {
                realTimeDataMapper.insert(e);
            }
        });


        return 1;
    }

    @Override
    public ComparisonVO comparison(Integer deviceId, String date) {
        if (StringUtils.isEmpty(date)) {
            date = DateUtil.today();
        }
        ComparisonVO comparisonVO = new ComparisonVO();
        // 按照 年 月 日 早 中 晚 的顺序处理数据，先处理上周期再处理本周期
        // 今年开始
        String currentYear = SpecificDateUtil.getCurrentYear(date);
        // 明年开始
        String nextYear = SpecificDateUtil.getNextYear(date);
        // 去年开始
        String prevYear = SpecificDateUtil.getPrevYear(date);
        //先处理去年的数据，如果去年的数据表内有直接取，否则需要查询Mongo
        Statistics statistics = statisticsMapper.selectOne(new LambdaQueryWrapper<Statistics>()
                .eq(Statistics::getDeviceId, deviceId)
                .orderByDesc(Statistics::getDate).last("limit 1"));
        BigDecimal prevYearVolume;
        BigDecimal prevYearFlow;
        if (ObjectUtils.isEmpty(statistics)) {
            List<HistoryData> prevVolumeData = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_VOLUME.getCode(), prevYear, currentYear);
            List<HistoryData> prevFlowData = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(), prevYear, currentYear);
            prevYearVolume = getHistoryData(prevVolumeData);
            prevYearFlow = getHistoryData(prevFlowData);
        } else {
            prevYearVolume = statistics.getLastYearVolume();
            prevYearFlow = statistics.getLastYearFlow();
        }
        comparisonVO.setLastYearVolume(prevYearVolume);
        comparisonVO.setLastYearFlow(prevYearFlow);
        //然后处理今年的数据，需要查询Mongo，先返回数据集合，后续所有处理都是用该集合，减少查询提高速度，注意程序结束清楚大集合
        System.out.println(System.currentTimeMillis());
        List<HistoryData> volumeData = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_VOLUME.getCode(), currentYear, nextYear);
        List<HistoryData> flowData = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(), currentYear, nextYear);
        System.out.println(System.currentTimeMillis());
        BigDecimal currentYearVolume = getHistoryData(volumeData);
        BigDecimal currentYearFlow = getHistoryData(flowData);
        comparisonVO.setCurrentYearVolume(currentYearVolume);
        comparisonVO.setCurrentYearFlow(currentYearFlow);
        // 上个月开始
        String prevMonthStr = SpecificDateUtil.getPrevMonth(date);
        // 本月开始
        String currentMonthStr = SpecificDateUtil.getCurrentMonth(date);
        // 下个月开始
        String nextMonthStr = SpecificDateUtil.getNextMonth(date);
        //上个月
        List<HistoryData> prevMonthVolumeData = getTimeSlotList(volumeData, prevMonthStr, currentMonthStr);
        List<HistoryData> prevMonthFlowData = getTimeSlotList(flowData, prevMonthStr, currentMonthStr);
        BigDecimal prevMonthVolume = getHistoryData(prevMonthVolumeData);
        BigDecimal prevMonthFlow = getHistoryData(prevMonthFlowData);
        comparisonVO.setLastMonthVolume(prevMonthVolume);
        comparisonVO.setLastMonthFlow(prevMonthFlow);
        prevMonthVolumeData.clear();
        prevMonthFlowData.clear();
        // 当月
        List<HistoryData> currentMonthVolumeData = getTimeSlotList(volumeData, currentMonthStr, nextMonthStr);
        List<HistoryData> currentMonthFlowData = getTimeSlotList(flowData, currentMonthStr, nextMonthStr);
        BigDecimal currentMonthVolume = getHistoryData(currentMonthVolumeData);
        BigDecimal currentMonthFlow = getHistoryData(currentMonthFlowData);
        comparisonVO.setCurrentMonthVolume(currentMonthVolume);
        comparisonVO.setCurrentMonthFlow(currentMonthFlow);
        currentMonthVolumeData.clear();
        currentMonthFlowData.clear();

        // 昨天开始
        String prevDayStr = SpecificDateUtil.getPrevDay(date);
        // 今天开始
        String currentDayStr = SpecificDateUtil.getCurrentDay(date);
        // 明天开始
        String nextDayStr = SpecificDateUtil.getNextDay(date);
        // 昨天
        List<HistoryData> prevDayVolumeData = getTimeSlotList(volumeData, prevDayStr, currentDayStr);
        List<HistoryData> prevDayFlowData = getTimeSlotList(flowData, prevDayStr, currentDayStr);
        BigDecimal prevDayVolume = getHistoryData(prevDayVolumeData);
        BigDecimal prevDayFlow = getHistoryData(prevDayFlowData);
        comparisonVO.setLastDayVolume(prevDayVolume);
        comparisonVO.setLastDayFlow(prevDayFlow);
        prevDayVolumeData.clear();
        prevDayFlowData.clear();

        // 今天
        List<HistoryData> currentDayVolumeData = getTimeSlotList(volumeData, currentDayStr, nextDayStr);
        List<HistoryData> currentDayFlowData = getTimeSlotList(flowData, currentDayStr, nextDayStr);
        BigDecimal currentDayVolume = getHistoryData(currentDayVolumeData);
        BigDecimal currentDayFlow = getHistoryData(currentDayFlowData);
        comparisonVO.setCurrentDayVolume(currentDayVolume);
        comparisonVO.setCurrentDayFlow(currentDayFlow);
        currentDayVolumeData.clear();
        currentDayFlowData.clear();

        handleClassInfo(date, comparisonVO, volumeData, flowData);

        volumeData.clear();
        flowData.clear();
        return comparisonVO;
    }

    @Override
    public List<Object> currentData(Integer deviceId, List<Integer> contents) {
        List<Object> dataList = new ArrayList<>();
        LedScreenDTO ledScreenDTO = new LedScreenDTO();
        String date = DateUtil.today();
        //查询所需数据
        List<Integer> dictValues = buildDictValues();
        List<RealTimeData> currentRealTimeDataList = realTimeDataMapper.selectList(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId)
                .in(RealTimeData::getDictValue, dictValues));
        Map<Integer, String> currentRealTimeMap = currentRealTimeDataList.stream().collect(Collectors.toMap(RealTimeData::getDictValue, RealTimeData::getDataValue));

        if (CollUtil.isNotEmpty(currentRealTimeDataList)) {
            // 当前带速
            String operateMode = currentRealTimeMap.get(DeviceCommandEnum.OPERATE_MODE.getCode());
            operateMode = ObjectUtils.isEmpty(operateMode) ? OperateModeEnum.UNIFORM_SPEED.getCode() : operateMode;
            if (OperateModeEnum.UNIFORM_SPEED.getCode().equals(operateMode)) {
                // 当前流量
                ledScreenDTO.setCurrent(CalculationUtils.toW(currentRealTimeMap.get(DeviceCommandEnum.CURRENT_FLOW.getCode())));
                ledScreenDTO.setSpeed(CalculationUtils.toW(currentRealTimeMap.get(DeviceCommandEnum.UNIFORM_SPEED.getCode())));
            } else {
                List<HistoryData> currentFlowData = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),2);
                BigDecimal currentData = getCurrentData(currentFlowData);
                ledScreenDTO.setCurrent(CalculationUtils.toW(currentData.toString()));
                ledScreenDTO.setSpeed(CalculationUtils.toW(currentRealTimeMap.get(DeviceCommandEnum.VARIABLE_SPEED.getCode())));
            }
            // 日
            DateTime currentDay = SpecificDateUtil.getMsCurrentDay(date);
            List<HistoryData> dayFlowList = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),currentDay);
            String dayFlow = getHistoryData(dayFlowList).toString();
            ledScreenDTO.setDay(dayFlow);
            // 月
            DateTime currentMonth = SpecificDateUtil.getMsCurrentMonth(date);
            List<HistoryData> monthFlowList = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),currentMonth);
            String monthFlow = getHistoryData(monthFlowList).toString();
            ledScreenDTO.setMonth(monthFlow);
            // 年
            DateTime currentYear = SpecificDateUtil.getMsCurrentYear(date);
            List<HistoryData> yearFlowList = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),currentYear);
            String yearFlow = getHistoryData(yearFlowList).toString();
            ledScreenDTO.setYear(yearFlow);
            // 全部
            List<HistoryData> allFlowList = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode());
            String allFlow = getHistoryData(allFlowList).toString();
            ledScreenDTO.setAll(allFlow);
        }
        //将数据全部放进缓存集合
        //瞬时
        dataList.add(Float.parseFloat(ledScreenDTO.getCurrent()));
        //带速
        dataList.add(Float.parseFloat(ledScreenDTO.getSpeed()));
        // 早 中 晚
        List<String> classInfoList = handleClassInfo(deviceId,date);
        for (String data : classInfoList) {
            dataList.add(Float.parseFloat(data));
        }
        // 日
        dataList.add(Float.parseFloat(ledScreenDTO.getDay()));
        // 月
        dataList.add(Double.parseDouble(ledScreenDTO.getMonth()));
        // 年
        dataList.add(Double.parseDouble(ledScreenDTO.getYear()));
        // 全部
        dataList.add(Double.parseDouble(ledScreenDTO.getAll()));

        return dataList;
    }

    @Override
    public List<Object> currentData(Integer deviceId) {
        List<Object> dataList = new ArrayList<>();
        LedScreenDTO ledScreenDTO = new LedScreenDTO();
        String date = DateUtil.today();
        List<SysDictData> shiftTimeList = DictUtils.getDictCache("everyday_shift_time");
        List<Integer> dictValues = buildDictValues();
        List<RealTimeData> currentRealTimeDataList = realTimeDataMapper.selectList(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId)
                .in(RealTimeData::getDictValue, dictValues));
        Map<Integer, String> currentRealTimeMap = currentRealTimeDataList.stream().collect(Collectors.toMap(RealTimeData::getDictValue, RealTimeData::getDataValue));

        for (SysDictData data : shiftTimeList) {
            String[] timeArray = data.getDictValue().split(",");
            DateTime startTime = DateUtil.parse(date+" "+timeArray[0], DatePattern.NORM_DATETIME_PATTERN);
            DateTime endTime = DateUtil.parse(date+" "+timeArray[1], DatePattern.NORM_DATETIME_PATTERN);

            boolean b = DateUtil.isIn(new Date(), startTime, endTime);
            if (b) {
                String operateMode = currentRealTimeMap.get(DeviceCommandEnum.OPERATE_MODE.getCode());
                operateMode = ObjectUtils.isEmpty(operateMode) ? OperateModeEnum.UNIFORM_SPEED.getCode() : operateMode;

                if (OperateModeEnum.UNIFORM_SPEED.getCode().equals(operateMode)) {
                    // 当前流量
                    ledScreenDTO.setCurrent(CalculationUtils.toW(currentRealTimeMap.get(DeviceCommandEnum.CURRENT_FLOW.getCode())));
                    ledScreenDTO.setSpeed(CalculationUtils.toW(currentRealTimeMap.get(DeviceCommandEnum.UNIFORM_SPEED.getCode())));
                } else {
                    List<HistoryData> currentFlowData = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),2);
                    BigDecimal currentData = getCurrentData(currentFlowData);
                    ledScreenDTO.setCurrent(CalculationUtils.toW(currentData.toString()));
                    ledScreenDTO.setSpeed(CalculationUtils.toW(currentRealTimeMap.get(DeviceCommandEnum.VARIABLE_SPEED.getCode())));
                }
                dataList.add(Float.parseFloat(ledScreenDTO.getCurrent()));
                dataList.add(Float.parseFloat(ledScreenDTO.getSpeed()));

                Map<Object, Object> timeStart = redisTemplate.opsForHash().entries(CacheKeyConstants.KEY);
                Object currentClass = timeStart.get(CacheKeyConstants.CURRENT_CLASS);

                if (currentClass!=null){
                    startTime =new DateTime(Long.parseLong(currentClass.toString()));
                }else {
                    startTime=new DateTime(0);
                }
                List<HistoryData> currentClassFlowData = getMsTimeSlotList(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(), startTime, endTime);
                BigDecimal currentClassFlow = getHistoryData(currentClassFlowData);
                double v = Double.parseDouble(currentClassFlow.toString());
                dataList.add(v);
                // 日
                Object day = timeStart.get(CacheKeyConstants.DAY);
                DateTime currentDay;
                if (day!=null){
                    currentDay = new DateTime(Long.parseLong(day.toString()));
                } else {
                    currentDay = new DateTime(0);
                }
                // 日
                List<HistoryData> dayFlowList = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),currentDay);
                String dayFlow = getHistoryData(dayFlowList).toString();
                ledScreenDTO.setDay(dayFlow);
                // 月
                Object month = timeStart.get(CacheKeyConstants.MONTH);
                DateTime currentMonth;
                if (month!=null){
                    currentMonth = new DateTime(Long.parseLong(month.toString()));
                }else {
                    currentMonth = new DateTime(0);
                }
                List<HistoryData> monthFlowList = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),currentMonth);
                String monthFlow = getHistoryData(monthFlowList).toString();
                ledScreenDTO.setMonth(monthFlow);
                // 年
                Object year = timeStart.get(CacheKeyConstants.YEAR);
                DateTime currentYear;
                if (year!=null){
                    currentYear = new DateTime(Long.parseLong(year.toString()));
                }else {
                    currentYear = new DateTime(0);
                }
                List<HistoryData> yearFlowList = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),currentYear);
                String yearFlow = getHistoryData(yearFlowList).toString();
                ledScreenDTO.setYear(yearFlow);
                // 日
                dataList.add(Double.parseDouble(ledScreenDTO.getDay()));
                // 月
                dataList.add(Double.parseDouble(ledScreenDTO.getMonth()));
                // 年
                dataList.add(Double.parseDouble(ledScreenDTO.getYear()));
            }
        }
        return dataList;
    }

    @Override
    public List<Object> currentData(Integer deviceId,String startTime,String endTime) {
        List<Object> dataList = new ArrayList<>();
        List<HistoryData> timeSlotList = getTimeSlotData(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(),startTime,endTime);
        BigDecimal prevMonthVolume = getHistoryData(timeSlotList);
        double doubleValue = prevMonthVolume.setScale(2, RoundingMode.HALF_UP).doubleValue();
        dataList.add(doubleValue);
        return  dataList;
    }

    private BigDecimal getCurrentData(List<HistoryData> allFlowData) {
        //变速计算两条时间间隔计算数据
        BigDecimal currentData = new BigDecimal("0.00");
        if (allFlowData.size() >= 2) {
            List<HistoryData> twoHistoryData = allFlowData.subList(allFlowData.size() - 2, allFlowData.size());
            Date lastTime = twoHistoryData.get(0).getCreateTime();
            Date firstTime = twoHistoryData.get(1).getCreateTime();
            long betweenTime = DateUtil.between(lastTime, firstTime, DateUnit.MS);
            BigDecimal intervalTime = new BigDecimal(betweenTime).divide(new BigDecimal(1000),2, RoundingMode.HALF_UP);

            BigDecimal lastData = new BigDecimal(twoHistoryData.get(0).getDataValue());
            BigDecimal firstData = new BigDecimal(twoHistoryData.get(1).getDataValue());
            if (intervalTime.compareTo(new BigDecimal("0")) > 0 && lastData.compareTo(firstData) >= 0) {
                // todo 保留小五位数
                currentData = lastData.subtract(firstData);
                currentData = currentData.divide(intervalTime, 5, RoundingMode.HALF_UP).multiply(new BigDecimal("3600"));
            }
        }
        return currentData;
    }


    private List<Integer> buildDictValues() {
        List<Integer> dictValues = new ArrayList<>();
        dictValues.add(DeviceCommandEnum.CURRENT_FLOW.getCode());
        dictValues.add(DeviceCommandEnum.CUMULATIVE_FLOW.getCode());
        dictValues.add(DeviceCommandEnum.OPERATE_MODE.getCode());
        dictValues.add(DeviceCommandEnum.SPEED.getCode());
        dictValues.add(DeviceCommandEnum.VARIABLE_SPEED.getCode());
        dictValues.add(DeviceCommandEnum.UNIFORM_SPEED.getCode());
        return dictValues;
    }


    private List<String> handleClassInfo(Integer deviceId,String date) {
        List<String> classInfoList = new ArrayList<>();
        List<SysDictData> shiftTimeList = DictUtils.getDictCache("everyday_shift_time");
        for (SysDictData data : shiftTimeList) {
            String[] timeArray = data.getDictValue().split(",");
            DateTime startTime, endTime;
            if (timeArray[0].startsWith("-")) {
                startTime = SpecificDateUtil.getMsCurrentClassTime(date, timeArray[0]);
            } else {
                startTime = SpecificDateUtil.getMsNextClassTime(date, timeArray[0]);
            }
            if (timeArray[1].startsWith("-")) {
                endTime = SpecificDateUtil.getMsCurrentClassTime(date, timeArray[1]);
            } else {
                endTime = SpecificDateUtil.getMsNextClassTime(date, timeArray[1]);
            }
            List<HistoryData> currentClassFlowData = getMsTimeSlotList(deviceId, DeviceCommandEnum.CUMULATIVE_FLOW.getCode(), startTime, endTime);
            BigDecimal currentClassFlow = getHistoryData(currentClassFlowData);
            if (LedScreenContent.MORNING.getInfo().equals(data.getDictLabel())) {
                classInfoList.add(currentClassFlow.toString());
            }
            if (LedScreenContent.NOON.getInfo().equals(data.getDictLabel())) {
                classInfoList.add(currentClassFlow.toString());
            }
            if (LedScreenContent.NIGHT.getInfo().equals(data.getDictLabel())) {
                classInfoList.add(currentClassFlow.toString());
            }
            currentClassFlowData.clear();
        }
        return classInfoList;
    }

    private void handleClassInfo(String date, ComparisonVO comparisonVO, List<HistoryData> volumeData, List<HistoryData> flowData) {
        List<SysDictData> shiftTime = DictUtils.getDictCache("everyday_shift_time");
        String morning = "早班", noon = "中班", night = "晚班";
        if (StringUtils.isNotNull(shiftTime)) {
            for (SysDictData data : shiftTime) {
                String[] timeArray = data.getDictValue().split(",");
                String startTime, endTime;
                if (timeArray[0].startsWith("-")) {
                    startTime = SpecificDateUtil.getPrevClassTime(date, timeArray[0]);
                } else {
                    startTime = SpecificDateUtil.getCurrentClassTime(date, timeArray[0]);
                }
                if (timeArray[1].startsWith("-")) {
                    endTime = SpecificDateUtil.getPrevClassTime(date, timeArray[1]);
                } else {
                    endTime = SpecificDateUtil.getCurrentClassTime(date, timeArray[1]);
                }
                List<HistoryData> prevClassVolumeData = getTimeSlotList(volumeData, startTime, endTime);
                List<HistoryData> prevClassFlowData = getTimeSlotList(flowData, startTime, endTime);
                BigDecimal prevClassVolume = getHistoryData(prevClassVolumeData);
                BigDecimal prevClassFlow = getHistoryData(prevClassFlowData);
                if (morning.equals(data.getDictLabel())) {
                    comparisonVO.setLastMorningVolume(prevClassVolume);
                    comparisonVO.setLastMorningFlow(prevClassFlow);
                }
                if (noon.equals(data.getDictLabel())) {
                    comparisonVO.setLastNoonVolume(prevClassVolume);
                    comparisonVO.setLastNoonFlow(prevClassFlow);
                }
                if (night.equals(data.getDictLabel())) {
                    comparisonVO.setLastNightVolume(prevClassVolume);
                    comparisonVO.setLastNightFlow(prevClassFlow);
                }
                prevClassVolumeData.clear();
                prevClassFlowData.clear();

                if (timeArray[0].startsWith("-")) {
                    startTime = SpecificDateUtil.getCurrentClassTime(date, timeArray[0]);
                } else {
                    startTime = SpecificDateUtil.getNextClassTime(date, timeArray[0]);
                }
                if (timeArray[1].startsWith("-")) {
                    endTime = SpecificDateUtil.getCurrentClassTime(date, timeArray[1]);
                } else {
                    endTime = SpecificDateUtil.getNextClassTime(date, timeArray[1]);
                }
                List<HistoryData> currentClassVolumeData = getTimeSlotList(volumeData, startTime, endTime);
                List<HistoryData> currentClassFlowData = getTimeSlotList(flowData, startTime, endTime);
                BigDecimal currentClassVolume = getHistoryData(currentClassVolumeData);
                BigDecimal currentClassFlow = getHistoryData(currentClassFlowData);

                if (morning.equals(data.getDictLabel())) {
                    comparisonVO.setCurrentMorningVolume(currentClassVolume);
                    comparisonVO.setCurrentMorningFlow(currentClassFlow);
                }
                if (noon.equals(data.getDictLabel())) {
                    comparisonVO.setCurrentNoonVolume(currentClassVolume);
                    comparisonVO.setCurrentNoonFlow(currentClassFlow);
                }
                if (night.equals(data.getDictLabel())) {
                    comparisonVO.setCurrentNightVolume(currentClassVolume);
                    comparisonVO.setCurrentNightFlow(currentClassFlow);
                }
                currentClassVolumeData.clear();
                currentClassFlowData.clear();
            }
        }
    }

    private List<HistoryData> getTimeSlotData(Integer deviceId, int dictValue) {
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").is(dictValue)
        );
        return getTimeHistoryData(criteria);
    }

    private List<HistoryData> getTimeSlotData(Integer deviceId, int dictValue,int limit) {
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").is(dictValue)
        );
        Sort descSort = Sort.by(Sort.Order.desc("createTime"));
        return mongoComponent.selectList(criteria, limit, descSort, HistoryData.class);
    }


    private List<HistoryData> getTimeSlotData(Integer deviceId, int dictValue, DateTime currentTime) {
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").is(dictValue),
                Criteria.where("createTime").gte(currentTime)
        );
        return getTimeHistoryData(criteria);
    }

    private List<HistoryData> getTimeSlotData(Integer deviceId, int dictValue, String startTime, String endTime) {
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").is(dictValue),
                Criteria.where("createTime").gte(new DateTime(startTime, DatePattern.NORM_DATETIME_FORMAT)),
                Criteria.where("createTime").lt(new DateTime(endTime, DatePattern.NORM_DATETIME_FORMAT))
        );
        return getTimeHistoryData(criteria);
    }

    private List<HistoryData> getTimeHistoryData(Criteria criteria) {
        List<HistoryData> result = new ArrayList<>();
        Sort ascSort = Sort.by(Sort.Order.asc("createTime"));
        Sort descSort = Sort.by(Sort.Order.desc("createTime"));
        List<HistoryData> startList = mongoComponent.selectList(criteria, 1, ascSort, HistoryData.class);
        if (CollUtil.isNotEmpty(startList)){
            result.add(startList.get(0));
        }
        List<HistoryData> endList = mongoComponent.selectList(criteria, 1, descSort, HistoryData.class);
        if (CollUtil.isNotEmpty(endList)){
            result.add(endList.get(0));
        }
        return result;
    }


    private BigDecimal getHistoryData(List<HistoryData> dataList) {
        BigDecimal result = new BigDecimal("0.00");
        BigDecimal zero = new BigDecimal("0.00");
        if (CollUtil.isNotEmpty(dataList)) {
            HistoryData maxhistoryData = dataList.get(dataList.size() - 1);
            HistoryData minhistoryData = dataList.get(0);
            BigDecimal max = new BigDecimal(maxhistoryData.getDataValue());
            BigDecimal min = new BigDecimal(minhistoryData.getDataValue());
            result = max.subtract(min);
            result = result.compareTo(zero) < 0 ? zero : result;
            // todo 保留两位小数
            result = result.setScale(2,RoundingMode.HALF_UP);
        }
        return result;
    }


    private List<HistoryData> getTimeSlotList(List<HistoryData> dataList, String startTimeStr, String endTimeStr) {
        LocalDateTime startTime = LocalDateTimeUtil.parse(startTimeStr, DatePattern.NORM_DATETIME_PATTERN);
        LocalDateTime endTime = LocalDateTimeUtil.parse(endTimeStr, DatePattern.NORM_DATETIME_PATTERN);
        List<HistoryData> handleList = dataList.stream()
                .filter(r -> !startTime.isAfter(LocalDateTimeUtil.of(r.getCreateTime()))
                        && endTime.isAfter(LocalDateTimeUtil.of(r.getCreateTime())))
                .collect(Collectors.toList());
        return handleList;
    }

    private List<HistoryData> getMsTimeSlotList(Integer deviceId, int dictValue, DateTime startTime,DateTime endTime){
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").is(dictValue),
                Criteria.where("createTime").gte(startTime),
                Criteria.where("createTime").lte(endTime)
        );
        return getTimeHistoryData(criteria);
    }

    @Override
    public BriefingVO briefing(BriefingVO briefingVO) {
        Criteria volumeCriteria = new Criteria();
        volumeCriteria.andOperator(
                Criteria.where("deviceId").is(briefingVO.getDeviceId()),
                Criteria.where("dictValue").is(DeviceCommandEnum.CUMULATIVE_VOLUME.getCode()),
                Criteria.where("createTime").gte(new DateTime(briefingVO.getStartTime(), DatePattern.NORM_DATETIME_FORMAT)),
                Criteria.where("createTime").lt(new DateTime(briefingVO.getEndTime(), DatePattern.NORM_DATETIME_FORMAT))
        );

        Criteria flowCriteria = new Criteria();
        flowCriteria.andOperator(
                Criteria.where("deviceId").is(briefingVO.getDeviceId()),
                Criteria.where("dictValue").is(DeviceCommandEnum.CUMULATIVE_FLOW.getCode()),
                Criteria.where("createTime").gte(new DateTime(briefingVO.getStartTime(), DatePattern.NORM_DATETIME_FORMAT)),
                Criteria.where("createTime").lt(new DateTime(briefingVO.getEndTime(), DatePattern.NORM_DATETIME_FORMAT))
        );

        Sort startSort = Sort.by(Sort.Order.asc("createTime"));
        Sort endSort = Sort.by(Sort.Order.desc("createTime"));
        List<HistoryData> startVolumeDataList = mongoComponent.selectList(volumeCriteria, 1, startSort, HistoryData.class);
        List<HistoryData> endVolumeDataList = mongoComponent.selectList(volumeCriteria, 1, endSort, HistoryData.class);

        if (StringUtils.isNull(startVolumeDataList) || startVolumeDataList.isEmpty()) {
            briefingVO.setVolume(new BigDecimal("0"));
        } else {
            BigDecimal volume = new BigDecimal(endVolumeDataList.get(0).getDataValue()).subtract(new BigDecimal(startVolumeDataList.get(0).getDataValue()));
            briefingVO.setVolume(volume);
            log.debug("设备编号:{},昨日流量数据：8006,开始时间：{},结束时间：{}", briefingVO.getDeviceId(), briefingVO.getStartTime(), briefingVO.getEndTime());
            log.debug("设备编号:{},昨日流量数据：8006,开始数据：{},结束数据：{}", briefingVO.getDeviceId(), startVolumeDataList.get(0).getDataValue(), endVolumeDataList.get(0).getDataValue());

        }
        log.debug("设备编号:{},昨日流量数据：8006,体积数据：{}", briefingVO.getDeviceId(), briefingVO.getVolume());
        List<HistoryData> startFlowDataList = mongoComponent.selectList(flowCriteria, 1, startSort, HistoryData.class);
        List<HistoryData> endFlowDataList = mongoComponent.selectList(flowCriteria, 1, endSort, HistoryData.class);

        if (StringUtils.isNull(startFlowDataList) || startFlowDataList.isEmpty()) {
            briefingVO.setFlow(new BigDecimal("0"));
        } else {
            BigDecimal flow = new BigDecimal(endFlowDataList.get(0).getDataValue()).subtract(new BigDecimal(startFlowDataList.get(0).getDataValue()));
            briefingVO.setFlow(flow);
            log.debug("设备编号:{},昨日流量数据：8007,开始时间：{},结束时间：{}", briefingVO.getDeviceId(), briefingVO.getStartTime(), briefingVO.getEndTime());
            log.debug("设备编号:{},昨日流量数据：8007,开始数据：{},结束数据：{}", briefingVO.getDeviceId(), startFlowDataList.get(0).getDataValue(), endFlowDataList.get(0).getDataValue());
        }
        log.debug("设备编号:{},昨日流量数据：8007,流量数据：{}", briefingVO.getDeviceId(), briefingVO.getFlow());

        return briefingVO;
    }

    @Override
    public List<RealTimeData> queryDataByDate(Long deviceId, Date startTime, Date endTime) {
        LambdaQueryWrapper<RealTimeData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(RealTimeData::getCreateTime, startTime);
        queryWrapper.le(RealTimeData::getCreateTime, endTime);
        queryWrapper.eq(RealTimeData::getDeviceId, deviceId);
        List<RealTimeData> list = list(queryWrapper);
        return list;
    }

    @Override
    public RealTimeData queryByDictValue(Integer deviceId, Integer dictValue) {
        LambdaQueryWrapper<RealTimeData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RealTimeData::getDictValue, dictValue);
        queryWrapper.eq(RealTimeData::getDeviceId, deviceId);
        RealTimeData realTimeData = realTimeDataMapper.selectOne(queryWrapper);
        return realTimeData;
    }

    @Override
    public RealTimeData currentFlow(Integer deviceId) {
        RealTimeData realTimeData = realTimeDataMapper.selectOne(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId)
                .eq(RealTimeData::getDictValue, DeviceCommandEnum.CURRENT_FLOW.getCode())
                .orderByDesc(RealTimeData::getCreateTime)
                .last("limit 1"));

        return realTimeData;
    }

    @Override
    public AjaxResult brokenLineData(Integer deviceId) {
        List<String> timeList = new ArrayList<>();
        List<String> volumeList = new ArrayList<>();
        List<String> weightList = new ArrayList<>();
        // 先获得班次时间
        LocalDateTime currentTime = LocalDateTime.now();
        DateTimeFormatter df = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
        DateTimeFormatter dataFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN);
        List<SysDictData> shiftTime = DictUtils.getDictCache("diagram_shift_time");
        String[] classTimes = new String[2];
        String name = "";
        String timeTitle = "";
        if (StringUtils.isNotNull(shiftTime)) {
            for (SysDictData data : shiftTime) {
                String[] timeArray = data.getDictValue().split(",");
                if (timeArray[0].startsWith("-")) {
                    timeArray[0] = timeArray[0].replace("-", "");
                    timeArray[0] = LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeArray[0])).plusDays(-1).format(df);
                    timeTitle = LocalDate.now().plusDays(-1).format(dataFormatter);
                } else {
                    timeArray[0] = LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeArray[0])).format(df);
                    timeTitle = LocalDate.now().format(dataFormatter);
                }
                timeTitle = timeTitle + "~";
                if (timeArray[1].startsWith("-")) {
                    timeArray[1] = timeArray[1].replace("-", "");
                    timeArray[1] = LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeArray[1])).plusDays(-1).format(df);
                    timeTitle = timeTitle + LocalDate.now().plusDays(-1).format(dataFormatter);
                } else {
                    timeArray[1] = LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeArray[1])).format(df);
                    timeTitle = timeTitle + LocalDate.now().format(dataFormatter);
                }
                LocalDateTime startLocalTime = LocalDateTimeUtil.parse(timeArray[0], DatePattern.NORM_DATETIME_PATTERN);
                LocalDateTime endLocalTime = LocalDateTimeUtil.parse(timeArray[1], DatePattern.NORM_DATETIME_PATTERN);
                if (currentTime.isAfter(endLocalTime)) {
                    timeArray[0] = startLocalTime.plusDays(1).format(df);
                    timeArray[1] = endLocalTime.plusDays(1).format(df);
                }
                classTimes = timeArray;
                name = data.getDictLabel();
            }
        }

        String startTime = classTimes[0];
        String endTime = classTimes[1];

        Criteria volumeCriteria = new Criteria();
        volumeCriteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").is(DeviceCommandEnum.CURRENT_VOLUME.getCode()),
                Criteria.where("createTime").gte(new DateTime(startTime, DatePattern.NORM_DATETIME_FORMAT)),
                Criteria.where("createTime").lt(new DateTime(endTime, DatePattern.NORM_DATETIME_FORMAT))
        );

        Criteria flowCriteria = new Criteria();
        flowCriteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").is(DeviceCommandEnum.CURRENT_FLOW.getCode()),
                Criteria.where("createTime").gte(new DateTime(startTime, DatePattern.NORM_DATETIME_FORMAT)),
                Criteria.where("createTime").lt(new DateTime(endTime, DatePattern.NORM_DATETIME_FORMAT))
        );

        Sort sort = Sort.by(Sort.Order.asc("createTime"));
        List<HistoryData> volumeDataList = mongoComponent.selectList(volumeCriteria, sort, HistoryData.class);
        List<HistoryData> weightDataList = mongoComponent.selectList(flowCriteria, sort, HistoryData.class);
        volumeDataList.forEach(data -> {
            volumeList.add(data.getDataValue());
            timeList.add(DateUtil.format(data.getCreateTime(), DatePattern.NORM_TIME_PATTERN));
        });
        weightDataList.forEach(data -> {
            weightList.add(data.getDataValue());
        });

        return AjaxResult.success()
                .put("timeTitle", timeTitle)
                .put("className", name)
                .put("timeData", timeList)
                .put("volumeData", volumeList)
                .put("weightData", weightList);
    }


    @Override
    public AjaxResult averageThickness(Integer deviceId) {
        List<Integer> params = buildThicknessParam();
        List<RealTimeData> currentList = realTimeDataMapper.selectList(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId).in(RealTimeData::getDictValue, params));
        Map<Integer, String> currentMap = handleCurrentData(currentList);

        LocalDateTime current = LocalDateTime.now();
        LocalDateTime oneMinuteTime = current.minusMinutes(1);
        LocalDateTime fiveMinuteTime = current.minusMinutes(5);
        LocalDateTime tenMinuteTime = current.minusMinutes(10);
        LocalDateTime thirtyMinuteTime = current.minusMinutes(30);
        LocalDateTime sixtyMinuteTime = current.minusMinutes(60);
        String sixtyMinuteTimeStr = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).format(sixtyMinuteTime);
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").in(params),
                Criteria.where("createTime").gte(new DateTime(sixtyMinuteTimeStr, DatePattern.NORM_DATETIME_FORMAT))
        );
        List<HistoryData> dataList = mongoComponent.selectList(criteria, HistoryData.class);
        Map<Integer, String> oneMinuteMap = getDataByTime(dataList, oneMinuteTime);
        Map<Integer, String> fiveMinuteMap = getDataByTime(dataList, fiveMinuteTime);
        Map<Integer, String> tenMinuteMap = getDataByTime(dataList, tenMinuteTime);
        Map<Integer, String> thirtyMinuteMap = getDataByTime(dataList, thirtyMinuteTime);
        Map<Integer, String> sixtyMinuteMap = getDataByTime(dataList, sixtyMinuteTime);
        List<AverageThicknessVO> result = getAverageThicknessVO(currentMap, oneMinuteMap, fiveMinuteMap, tenMinuteMap, thirtyMinuteMap, sixtyMinuteMap);
        return AjaxResult.success(result);
    }

    @Override
    public AjaxResult averageThickness1(Integer deviceId) {
        List<Integer> params = buildThicknessParam();
        List<RealTimeData> currentList = realTimeDataMapper.selectList(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId).in(RealTimeData::getDictValue, params));
        Map<Integer, String> currentMap = handleCurrentData(currentList);

        LocalDateTime current = LocalDateTime.now();
        LocalDateTime oneMinuteTime = current.minusMinutes(1);
        LocalDateTime fiveMinuteTime = current.minusMinutes(5);
        LocalDateTime tenMinuteTime = current.minusMinutes(10);
        LocalDateTime thirtyMinuteTime = current.minusMinutes(30);
        LocalDateTime sixtyMinuteTime = current.minusMinutes(60);
        String sixtyMinuteTimeStr = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).format(sixtyMinuteTime);
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").in(params),
                Criteria.where("createTime").gte(new DateTime(sixtyMinuteTimeStr, DatePattern.NORM_DATETIME_FORMAT))
        );
        List<HistoryData> dataList = mongoComponent.selectList(criteria, HistoryData.class);
        Map<Integer, String> oneMinuteMap = getDataByTime(dataList, oneMinuteTime);
        Map<Integer, String> fiveMinuteMap = getDataByTime(dataList, fiveMinuteTime);
        Map<Integer, String> tenMinuteMap = getDataByTime(dataList, tenMinuteTime);
        Map<Integer, String> thirtyMinuteMap = getDataByTime(dataList, thirtyMinuteTime);
        Map<Integer, String> sixtyMinuteMap = getDataByTime(dataList, sixtyMinuteTime);
        List<List<String>> result = new ArrayList<>();

        result.add(convert(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode(), oneMinuteMap, fiveMinuteMap, tenMinuteMap, thirtyMinuteMap, sixtyMinuteMap));
        result.add(convert(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode(), oneMinuteMap, fiveMinuteMap, tenMinuteMap, thirtyMinuteMap, sixtyMinuteMap));
        result.add(convert(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode(), oneMinuteMap, fiveMinuteMap, tenMinuteMap, thirtyMinuteMap, sixtyMinuteMap));
        result.add(convert(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode(), oneMinuteMap, fiveMinuteMap, tenMinuteMap, thirtyMinuteMap, sixtyMinuteMap));
        return AjaxResult.success(result);
    }

    public List<String> convert(Integer code, Map<Integer, String> oneMinuteMap, Map<Integer, String> fiveMinuteMap, Map<Integer, String> tenMinuteMap, Map<Integer, String> thirtyMinuteMap, Map<Integer, String> sixtyMinuteMap) {
        ArrayList<String> result = new ArrayList<>();
        result.add(oneMinuteMap.get(code));
        result.add(fiveMinuteMap.get(code));
        result.add(tenMinuteMap.get(code));
        result.add(thirtyMinuteMap.get(code));
        result.add(sixtyMinuteMap.get(code));
        return result;
    }

    @Override
    public AjaxResult sectionData(Integer deviceId) {
        List<Integer> params = new ArrayList<>();
        params.add(SieveRadarCommandEnum.X_POINT.getCode());
        params.add(SieveRadarCommandEnum.Y_POINT.getCode());
        List<RealTimeData> currentList = realTimeDataMapper.selectList(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId).in(RealTimeData::getDictValue, params));

        List<String> xPoint = new ArrayList<>();
        List<String> yPoint = new ArrayList<>();
        if (currentList.isEmpty()) {
            for (int i = 0; i < 96; i++) {
                xPoint.add("0.0");
                yPoint.add("0.0");
            }
        } else {
            Map<Integer, String> data = currentList.stream()
                    .collect(Collectors.toMap(RealTimeData::getDictValue, RealTimeData::getDataValue, (oldValue, newValue) -> newValue));
            String xPointStr = data.get(SieveRadarCommandEnum.X_POINT.getCode());
            String yPointStr = data.get(SieveRadarCommandEnum.Y_POINT.getCode());
            xPoint = JSONArray.parseArray(xPointStr).toJavaList(String.class);
            yPoint = JSONArray.parseArray(yPointStr).toJavaList(String.class);
        }
        return AjaxResult.success().put("xPoint", xPoint).put("yPoint", yPoint);
    }

    @Override
    public AjaxResult trendData(Integer deviceId) {
        List<String> xPoints = new ArrayList<>();
        List<String> yAllPoints = new ArrayList<>();
        List<String> yLeftPoints = new ArrayList<>();
        List<String> yMiddlePoints = new ArrayList<>();
        List<String> yRightPoints = new ArrayList<>();

        List<Integer> params = buildThicknessParam();
        LocalDateTime current = LocalDateTime.now();
        LocalDateTime thirtyMinuteTime = current.minusMinutes(30);
        String thirtyMinuteTimeStr = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).format(thirtyMinuteTime);
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").in(params),
                Criteria.where("createTime").gte(new DateTime(thirtyMinuteTimeStr, DatePattern.NORM_DATETIME_FORMAT))
        );
        List<HistoryData> dataList = mongoComponent.selectList(criteria, HistoryData.class);
        for (int i = 30; i >= 0; i--) {
            LocalDateTime startTime = current.minusMinutes(i - 1);
            LocalDateTime endTime = current.minusMinutes(i);
            String timeStr = DateTimeFormatter.ofPattern("HH:mm").format(endTime);
            xPoints.add(timeStr);
            List<HistoryData> handleList = dataList.stream()
                    .filter(r -> startTime.compareTo(LocalDateTimeUtil.of(r.getCreateTime())) > 0
                            && endTime.compareTo(LocalDateTimeUtil.of(r.getCreateTime())) <= 0)
                    .collect(Collectors.toList());

            Map<Integer, List<HistoryData>> dataMap = handleList.stream().collect(Collectors.groupingBy(HistoryData::getDictValue));

            List<HistoryData> allSieveData = dataMap.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode());
            handleYPointData(yAllPoints, allSieveData);

            List<HistoryData> leftSieveData = dataMap.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode());
            handleYPointData(yLeftPoints, leftSieveData);

            List<HistoryData> middleSieveData = dataMap.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode());
            handleYPointData(yMiddlePoints, middleSieveData);

            List<HistoryData> rightSieveData = dataMap.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode());
            handleYPointData(yRightPoints, rightSieveData);
        }

        return AjaxResult.success().put("xPoints", xPoints).put("yAllPoints", yAllPoints).put("yLeftPoints", yLeftPoints).put("yMiddlePoints", yMiddlePoints).put("yRightPoints", yRightPoints);
    }

    @Override
    public Map<Integer, String> thicknessAlarmData(Integer deviceId) {
        Map<Integer, String> result = new HashMap<>(16);
        List<Integer> params = buildThicknessParam();
        LocalDateTime current = LocalDateTime.now();
        LocalDateTime thirtyMinuteTime = current.minusMinutes(5);
        if (demoService.getRedisPoliceFlag(DemoEnum.coalDistribution) || demoService.getRedisPoliceFlag(DemoEnum.coalHigh)) {
            thirtyMinuteTime = current.minusMinutes(1);
        }
        String thirtyMinuteTimeStr = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).format(thirtyMinuteTime);
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").in(params),
                Criteria.where("createTime").gte(new DateTime(thirtyMinuteTimeStr, DatePattern.NORM_DATETIME_FORMAT))
        );
        List<HistoryData> dataList = mongoComponent.selectList(criteria, HistoryData.class);
        thicknessAverage(result, dataList);
        return result;
    }

    @Override
    public AjaxResult proportionData(Integer deviceId) {
        List<String> timeList = new ArrayList<>();
        List<String> lumpCoalList = new ArrayList<>();
        List<String> slackList = new ArrayList<>();
        List<String> sieveList = new ArrayList<>();
        List<String> otherList = new ArrayList<>();

        List<Integer> params = buildProportionParam();
        LocalDateTime current = LocalDateTime.now();
        LocalDateTime thirtyMinuteTime = current.minusMinutes(30);
        String thirtyMinuteTimeStr = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).format(thirtyMinuteTime);
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").in(params),
                Criteria.where("createTime").gte(new DateTime(thirtyMinuteTimeStr, DatePattern.NORM_DATETIME_FORMAT))
        );
        List<HistoryData> dataList = mongoComponent.selectList(criteria, HistoryData.class);
        for (int i = 30; i >= 0; i--) {
            LocalDateTime startTime = current.minusMinutes(i - 1);
            LocalDateTime endTime = current.minusMinutes(i);
            String timeStr = DateTimeFormatter.ofPattern("HH:mm").format(endTime);
            timeList.add(timeStr);
            List<HistoryData> handleList = dataList.stream()
                    .filter(r -> startTime.compareTo(LocalDateTimeUtil.of(r.getCreateTime())) > 0
                            && endTime.compareTo(LocalDateTimeUtil.of(r.getCreateTime())) <= 0)
                    .collect(Collectors.toList());

            Map<Integer, List<HistoryData>> dataMap = handleList.stream().collect(Collectors.groupingBy(HistoryData::getDictValue));

            List<HistoryData> lumpCoalData = dataMap.get(PictureRecognitionEnum.LUMP_COAL.getCode());
            handleProportionData(lumpCoalList, lumpCoalData);

            List<HistoryData> slackData = dataMap.get(PictureRecognitionEnum.SLACK.getCode());
            handleProportionData(slackList, slackData);

            List<HistoryData> sieveData = dataMap.get(PictureRecognitionEnum.SIEVE.getCode());
            handleProportionData(sieveList, sieveData);

            List<HistoryData> otherData = dataMap.get(PictureRecognitionEnum.OTHER.getCode());
            handleProportionData(otherList, otherData);
        }

        return AjaxResult.success().put("timeList", timeList).put("lumpCoalList", lumpCoalList).put("slackList", slackList).put("sieveList", sieveList).put("otherList", otherList);
    }

    private Map<Integer, String> handleCurrentData(List<RealTimeData> currentList) {
        Map<Integer, String> result = new HashMap<>(16);
        if (currentList.isEmpty()) {
            result.put(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode(), "0.0");
            result.put(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode(), "0.0");
            result.put(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode(), "0.0");
            result.put(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode(), "0.0");
        } else {
            result = currentList.stream()
                    .collect(Collectors.toMap(RealTimeData::getDictValue, realTimeData -> new BigDecimal(realTimeData.getDataValue()).setScale(1, RoundingMode.HALF_UP).toString(), (oldValue, newValue) -> newValue));
        }
        return result;
    }

    private Map<Integer, String> getDataByTime(List<HistoryData> dataList, LocalDateTime minuteTime) {
        Map<Integer, String> result = new HashMap<>(16);
        List<HistoryData> minuteList = dataList.stream()
                .filter(r -> minuteTime.compareTo(LocalDateTimeUtil.of(r.getCreateTime())) <= 0)
                .collect(Collectors.toList());
        thicknessAverage(result, minuteList);
        return result;
    }

    private void thicknessAverage(Map<Integer, String> result, List<HistoryData> dataList) {
        Map<Integer, List<HistoryData>> dataMap = dataList.stream().collect(Collectors.groupingBy(HistoryData::getDictValue));

        List<HistoryData> allSieveData = dataMap.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode());
        handleData(result, SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode(), allSieveData);

        List<HistoryData> leftSieveData = dataMap.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode());
        handleData(result, SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode(), leftSieveData);

        List<HistoryData> middleSieveData = dataMap.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode());
        handleData(result, SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode(), middleSieveData);

        List<HistoryData> rightSieveData = dataMap.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode());
        handleData(result, SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode(), rightSieveData);
    }

    private void handleData(Map<Integer, String> result, Integer key, List<HistoryData> dataList) {
        if (StringUtils.isNull(dataList) || dataList.isEmpty()) {
            result.put(key, "0.0");
        } else {
            OptionalDouble allSieveAverage = dataList.stream()
                    .mapToDouble(historyData -> Double.parseDouble(historyData.getDataValue())).average();
            String value = new BigDecimal(String.valueOf(allSieveAverage.getAsDouble())).setScale(1, RoundingMode.HALF_UP).toString();
            result.put(key, value);
        }
    }

    private List<Integer> buildThicknessParam() {
        List<Integer> params = new ArrayList<>();
        params.add(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode());
        params.add(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode());
        params.add(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode());
        params.add(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode());
        return params;
    }

    private List<Integer> buildProportionParam() {
        List<Integer> params = new ArrayList<>();
        params.add(PictureRecognitionEnum.LUMP_COAL.getCode());
        params.add(PictureRecognitionEnum.SLACK.getCode());
        params.add(PictureRecognitionEnum.SIEVE.getCode());
        params.add(PictureRecognitionEnum.OTHER.getCode());
        return params;
    }

    private void handleYPointData(List<String> result, List<HistoryData> dataList) {
        if (StringUtils.isNull(dataList) || dataList.isEmpty()) {
            result.add("0.0");
        } else {
            OptionalDouble allSieveAverage = dataList.stream()
                    .mapToDouble(historyData -> Double.parseDouble(historyData.getDataValue())).average();
            String value = new BigDecimal(String.valueOf(allSieveAverage.getAsDouble())).setScale(1, RoundingMode.HALF_UP).toString();
            result.add(value);
        }
    }

    private void handleProportionData(List<String> result, List<HistoryData> dataList) {
        if (StringUtils.isNull(dataList) || dataList.isEmpty()) {
            result.add("0.0");
        } else {
            String value = new BigDecimal(dataList.get(0).getDataValue()).setScale(1, RoundingMode.HALF_UP).toString();
            result.add(value);
        }
    }

    private List<AverageThicknessVO> getAverageThicknessVO(Map<Integer, String> currentMap
            , Map<Integer, String> oneMinuteMap, Map<Integer, String> fiveMinuteMap
            , Map<Integer, String> tenMinuteMap, Map<Integer, String> thirtyMinuteMap
            , Map<Integer, String> sixtyMinuteMap) {

        List<AverageThicknessVO> result = new ArrayList<>();
        AverageThicknessVO allAverageThicknessVO = new AverageThicknessVO();
        allAverageThicknessVO.setDictValue(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode());
        allAverageThicknessVO.setPosition(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getInfo());
        allAverageThicknessVO.setCurrent(currentMap.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode()));
        allAverageThicknessVO.setOneMinute(oneMinuteMap.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode()));
        allAverageThicknessVO.setFiveMinute(fiveMinuteMap.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode()));
        allAverageThicknessVO.setTenMinute(tenMinuteMap.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode()));
        allAverageThicknessVO.setThirtyMinute(thirtyMinuteMap.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode()));
        allAverageThicknessVO.setSixtyMinute(sixtyMinuteMap.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode()));
        result.add(allAverageThicknessVO);

        AverageThicknessVO leftAverageThicknessVO = new AverageThicknessVO();
        leftAverageThicknessVO.setDictValue(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode());
        leftAverageThicknessVO.setPosition(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getInfo());
        leftAverageThicknessVO.setCurrent(currentMap.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode()));
        leftAverageThicknessVO.setOneMinute(oneMinuteMap.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode()));
        leftAverageThicknessVO.setFiveMinute(fiveMinuteMap.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode()));
        leftAverageThicknessVO.setTenMinute(tenMinuteMap.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode()));
        leftAverageThicknessVO.setThirtyMinute(thirtyMinuteMap.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode()));
        leftAverageThicknessVO.setSixtyMinute(sixtyMinuteMap.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode()));
        result.add(leftAverageThicknessVO);

        AverageThicknessVO middleAverageThicknessVO = new AverageThicknessVO();
        middleAverageThicknessVO.setDictValue(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode());
        middleAverageThicknessVO.setPosition(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getInfo());
        middleAverageThicknessVO.setCurrent(currentMap.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode()));
        middleAverageThicknessVO.setOneMinute(oneMinuteMap.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode()));
        middleAverageThicknessVO.setFiveMinute(fiveMinuteMap.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode()));
        middleAverageThicknessVO.setTenMinute(tenMinuteMap.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode()));
        middleAverageThicknessVO.setThirtyMinute(thirtyMinuteMap.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode()));
        middleAverageThicknessVO.setSixtyMinute(sixtyMinuteMap.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode()));
        result.add(middleAverageThicknessVO);

        AverageThicknessVO rightAverageThicknessVO = new AverageThicknessVO();
        rightAverageThicknessVO.setDictValue(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode());
        rightAverageThicknessVO.setPosition(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getInfo());
        rightAverageThicknessVO.setCurrent(currentMap.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode()));
        rightAverageThicknessVO.setOneMinute(oneMinuteMap.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode()));
        rightAverageThicknessVO.setFiveMinute(fiveMinuteMap.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode()));
        rightAverageThicknessVO.setTenMinute(tenMinuteMap.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode()));
        rightAverageThicknessVO.setThirtyMinute(thirtyMinuteMap.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode()));
        rightAverageThicknessVO.setSixtyMinute(sixtyMinuteMap.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode()));
        result.add(rightAverageThicknessVO);

        return result;
    }

}
